-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[Clang] fix confusing diagnostics for lambdas with init-captures inside braced initializers #166180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…de braced initializers
|
@llvm/pr-subscribers-clang Author: Oleksandr T. (a-tarasyuk) ChangesFixes #163498 This PR addresses the issue of confusing diagnostics for lambdas with init-captures appearing inside braced initializers. Cases such as: S s{[a(42), &] {}};were misparsed as C99 array designators, producing unrelated diagnostics, such as llvm-project/clang/lib/Parse/ParseInit.cpp Line 470 in bb9bd5f
llvm-project/clang/include/clang/Parse/Parser.h Lines 4652 to 4655 in bb9bd5f
llvm-project/clang/lib/Parse/ParseExprCXX.cpp Lines 871 to 879 in 24c22b7
The tentative parser now returns Clang now correctly recognizes such constructs as malformed lambda introducers and emits the expected diagnostic — for example, “capture-default must be first” — consistent with direct initialization cases such as: S s([a(42), &] {});Full diff: https://github.com/llvm/llvm-project/pull/166180.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92fc9381a5868..63faf46895989 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -496,6 +496,7 @@ Bug Fixes to C++ Support
nontrivial member when another member has an initializer. (#GH81774)
- Fixed a template depth issue when parsing lambdas inside a type constraint. (#GH162092)
- Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753)
+- Fix incorrect diagnostics for lambdas with init-captures inside braced initializers. (#GH163498)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 74f87a8cb63c3..03ae727168df0 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -772,9 +772,10 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// Produce a diagnostic if we're not tentatively parsing; otherwise track
// that our parse has failed.
- auto Invalid = [&](llvm::function_ref<void()> Action) {
+ auto Result = [&](llvm::function_ref<void()> Action,
+ LambdaIntroducerTentativeParse State) {
if (Tentative) {
- *Tentative = LambdaIntroducerTentativeParse::Invalid;
+ *Tentative = State;
return false;
}
Action();
@@ -824,9 +825,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
break;
}
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
- });
+ return Result(
+ [&] {
+ Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
}
ConsumeToken();
}
@@ -861,9 +864,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
ConsumeToken();
Kind = LCK_StarThis;
} else {
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
- });
+ return Result(
+ [&] {
+ Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
}
} else if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
@@ -875,8 +880,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// or the start of a capture (in the "&" case) with the rest of the
// capture missing. Both are an error but a misplaced capture-default
// is more likely if we don't already have a capture default.
- return Invalid(
- [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); });
+ return Result(
+ [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); },
+ LambdaIntroducerTentativeParse::Incomplete);
} else {
TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
@@ -899,14 +905,16 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
- return Invalid([&] {
- // FIXME: Suggest a fixit here.
- Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
- });
+ return Result(
+ [&] {
+ // FIXME: Suggest a fixit here.
+ Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
} else {
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_capture);
- });
+ return Result(
+ [&] { Diag(Tok.getLocation(), diag::err_expected_capture); },
+ LambdaIntroducerTentativeParse::Invalid);
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
diff --git a/clang/test/Parser/lambda-misplaced-capture-default.cpp b/clang/test/Parser/lambda-misplaced-capture-default.cpp
index d65b875102da7..4f5bd6d7fa5e9 100644
--- a/clang/test/Parser/lambda-misplaced-capture-default.cpp
+++ b/clang/test/Parser/lambda-misplaced-capture-default.cpp
@@ -36,3 +36,12 @@ template <typename... Args> void Test(Args... args) {
[... xs = &args, &] {}; // expected-error {{capture default must be first}}
}
} // namespace misplaced_capture_default_pack
+
+namespace GH163498 {
+struct S {
+ template <class T> S(T) {}
+};
+void t() {
+ S s{[a(42), &] {}}; // expected-error {{capture default must be first}}
+}
+}
|
… into fix/163498
AaronBallman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
…de braced initializers (llvm#166180) Fixes llvm#163498 --- This PR addresses the issue of confusing diagnostics for lambdas with init-captures appearing inside braced initializers. Cases such as: ```cpp S s{[a(42), &] {}}; ``` were misparsed as C99 array designators, producing unrelated diagnostics, such as `use of undeclared identifier 'a'`, and `expected ']'` --- https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/lib/Parse/ParseInit.cpp#L470 https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/lib/Parse/ParseInit.cpp#L74 https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/include/clang/Parse/Parser.h#L4652-L4655 https://github.com/llvm/llvm-project/blob/24c22b7de620669aed9da28de323309c44a58244/clang/lib/Parse/ParseExprCXX.cpp#L871-L879 The tentative parser now returns `Incomplete` for partially valid lambda introducers, preserving the `lambda` interpretation and allowing the proper diagnostic to be issued later. --- Clang now correctly recognizes such constructs as malformed lambda introducers and emits the expected diagnostic — for example, “capture-default must be first” — consistent with direct initialization cases such as: ```cpp S s([a(42), &] {}); ```
Fixes #163498
This PR addresses the issue of confusing diagnostics for lambdas with init-captures appearing inside braced initializers.
Cases such as:
S s{[a(42), &] {}};were misparsed as C99 array designators, producing unrelated diagnostics, such as
use of undeclared identifier 'a', andexpected ']'llvm-project/clang/lib/Parse/ParseInit.cpp
Line 470 in bb9bd5f
llvm-project/clang/lib/Parse/ParseInit.cpp
Line 74 in bb9bd5f
llvm-project/clang/include/clang/Parse/Parser.h
Lines 4652 to 4655 in bb9bd5f
llvm-project/clang/lib/Parse/ParseExprCXX.cpp
Lines 871 to 879 in 24c22b7
The tentative parser now returns
Incompletefor partially valid lambda introducers, preserving thelambdainterpretation and allowing the proper diagnostic to be issued later.Clang now correctly recognizes such constructs as malformed lambda introducers and emits the expected diagnostic — for example, “capture-default must be first” — consistent with direct initialization cases such as: